﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Devonline.Core;
using Devonline.Entity;
using Devonline.Http;
using Devonline.Utils;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ProjectManagement.Models;

namespace ProjectManagement.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
    public class AttachmentsController : ControllerBase
    {
        private readonly ApplicationDbContext _context;

        public AttachmentsController(ApplicationDbContext context)
        {
            _context = context;
        }

        [HttpGet]
        public async Task<IActionResult> GetAsync()
        {
            try
            {
                string businessType = Request.GetRequestOption<string>(nameof(businessType));
                string businessKey = Request.GetRequestOption<string>(nameof(businessKey));
                if (businessType.IsNotNullOrEmpty() || businessKey.IsNotNullOrEmpty())
                {
                    var queryable = _context.Attachments.AsQueryable();
                    if (businessType.IsNotNullOrEmpty())
                    {
                        queryable = queryable.Where(x => x.BusinessType == businessType);
                    }

                    if (businessKey.IsNotNullOrEmpty())
                    {
                        queryable = queryable.Where(x => x.BusinessKey == businessKey);
                    }

                    return Ok(await queryable.ToListAsync());
                }

                return NotFound();
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpGet("Download")]
        public async Task<IActionResult> Download(string fileName)
        {
            try
            {
                fileName ??= Request.GetRequestOption<string>(nameof(fileName));
                if (fileName.IsNullOrEmpty())
                {
                    throw new Exception("没有提交文件名!");
                }

                string filePath = Request.GetRequestOption<string>(nameof(filePath));
                filePath = filePath.IsNullOrEmpty() ? fileName : Path.Combine(filePath, fileName);
                var attachment = await _context.GetQueryable<Attachment>().FirstOrDefaultAsync(x => x.Path == filePath).ConfigureAwait(false);
                var fileInfo = new FileInfo((attachment?.Path ?? fileName).GetAttachmentPath());
                if (fileInfo.Exists)
                {
                    return File(fileInfo.OpenRead(), attachment?.ContentType ?? AppSettings.CONTENT_TYPE_OF_STREAM, attachment?.Name ?? fileName);
                }

                return NotFound();
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        /// <summary>
        /// 获取系统已在库的可访问文件
        /// 文件路径只支持一级路径, 适用于访问自动保存的文件或者符合目录规范的文件
        /// </summary>
        /// <param name="filePath">文件路径(只支持一级路径)</param>
        /// <param name="fileName">文件名</param>
        /// <returns></returns>
        [HttpGet("Files/{filePath}/{fileName}")]
        public async Task<IActionResult> Files(string filePath, string fileName)
        {
            try
            {
                filePath = filePath.IsNullOrEmpty() ? fileName : Path.Combine(filePath, fileName);
                var attachment = await _context.GetQueryable<Attachment>().FirstOrDefaultAsync(x => x.Path == filePath).ConfigureAwait(false);
                var fileInfo = new FileInfo((attachment?.Path ?? filePath).GetAttachmentPath());
                if (fileInfo.Exists)
                {
                    return File(fileInfo.OpenRead(), attachment?.ContentType ?? AppSettings.CONTENT_TYPE_OF_STREAM, attachment?.Name ?? fileName);
                }

                return NotFound();
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpPost("Upload")]
        public async Task<IActionResult> Upload(IEnumerable<IFormFile> files)
        {
            try
            {
                if (files.IsNullOrEmpty() && Request.HasFormContentType && Request.Form.Files.IsNotNullOrEmpty())
                {
                    files = Request.Form.Files;
                }

                var uploadResults = await files.UploadFilesAsync<Attachment, string>();
                return uploadResults.Any(x => x.StatusCode == HttpStatusCode.OK) ? Ok(uploadResults) : (IActionResult)BadRequest(uploadResults);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpDelete("Delete")]
        public async Task<IActionResult> Delete(string fileNames)
        {
            try
            {
                fileNames ??= Request.GetRequestOption<string>(nameof(fileNames));
                if (fileNames.IsNullOrEmpty())
                {
                    return BadRequest("请输入要删除的文件名!");
                }

                var files = fileNames.Split(AppSettings.CHAR_COMMA, StringSplitOptions.RemoveEmptyEntries);
                var attachments = await _context.GetQueryable<Attachment>().Where(x => files.Contains(x.Path)).ToListAsync().ConfigureAwait(false);
                if (attachments.IsNotNullOrEmpty())
                {
                    _context.RemoveRange(attachments);
                    await _context.SaveChangesAsync().ConfigureAwait(true);
                }

                if (files.IsNotNullOrEmpty())
                {
                    foreach (var file in files)
                    {
                        try
                        {
                            var filePath = file.GetAttachmentPath();
                            if (System.IO.File.Exists(filePath))
                            {
                                System.IO.File.Delete(filePath);
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.Exception($"文件 {file} 删除失败!", ex);
                        }
                    }
                }

                return Ok();
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }
    }
}
